package com.hengfoxwolf.flowborderrectdemo
import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Path
import android.graphics.Rect
import android.util.AttributeSet
import android.util.Log
import android.view.View
import kotlinx.coroutines.*

class FlowBorderRect @JvmOverloads constructor(
    context: Context,
    attributeSet: AttributeSet? = null
) : View(context, attributeSet), CoroutineScope by MainScope() {

    private val defaultWidth = context.resources.getDimension(R.dimen.dp_200).toInt()
    private val defaultHeight = context.resources.getDimension(R.dimen.dp_60).toInt()

    private val rectPaint by lazy {
        Paint().apply {
            isDither = true
            isAntiAlias = true
            color = context.resources.getColor(R.color.purple_700)
            style = Paint.Style.STROKE
            strokeWidth = context.resources.getDimension(R.dimen.dp_2)
        }
    }

    private val pathPaint by lazy {
        Paint().apply {
            isDither = true
            isAntiAlias = true
            style = Paint.Style.STROKE
            color = context.resources.getColor(R.color.red)
            strokeWidth = context.resources.getDimension(R.dimen.dp_2)
        }
    }

    private val rect by lazy {
        Rect()
    }

    private val path by lazy {
        Path()
    }

    private var xToRight = 0F
    private var yToBottom = 0F
    private var xToLeft = 0F
    private var yToTop = 0F

    private var xStep = 0F
    private var yStep = 0F

    private var job: Job? = null

    override fun onFinishInflate() {
        super.onFinishInflate()

        job = launch {
            delay(1000)
            while (true) {
                if (Math.round(xToRight) < measuredWidth) {
                    delay(500)
                    xToRight += xStep
                } else {
                    if (Math.round(yToBottom) < measuredHeight) {
                        delay(500)
                        yToBottom += yStep
                    } else {
                        if (Math.round(xToLeft) < measuredWidth) {
                            delay(500)
                            xToLeft += xStep
                        } else {
                            if (Math.round(yToTop) < measuredHeight) {
                                delay(500)
                                yToTop += yStep
                            }
                        }
                    }
                }

                if (Math.round(yToTop) >= measuredHeight) {
                    xToRight = 0F
                    yToBottom = 0F
                    xToLeft = 0F
                    yToTop = 0F
                    path.reset()
                }

                invalidate()
            }
        }

        job?.start()
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        setMeasuredDimension(
            defaultWidth - paddingStart - paddingEnd,
            defaultHeight - paddingTop - paddingBottom
        )

        xStep = measuredWidth.toFloat() / HORIZONTAL_PIECES
        yStep = measuredHeight.toFloat() / VERTICAL_PIECES
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        canvas?.apply {
            rect.set(
                0,
                0,
                measuredWidth,
                measuredHeight
            )
            drawRect(rect, rectPaint)

            path.moveTo(0F, 0F)

            path.lineTo(Math.min(Math.round(xToRight), measuredWidth).toFloat(), 0F)

            if (Math.round(xToRight) >= measuredWidth) {
                path.lineTo(measuredWidth.toFloat(), Math.min(Math.round(yToBottom), measuredHeight).toFloat())
            }

            if (Math.round(yToBottom) >= measuredHeight) {
                path.lineTo((measuredWidth - Math.min(Math.round(xToLeft), measuredWidth)).toFloat(), measuredHeight.toFloat())
            }

            if (Math.round(xToLeft) >= measuredWidth) {
                path.lineTo(0F, (measuredHeight - Math.min(Math.round(yToTop), measuredHeight)).toFloat())
            }

            drawPath(path, pathPaint)
        }
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        job?.cancel()
    }

    companion object {
        const val TAG = "FlowBorderRect"
        const val HORIZONTAL_PIECES = 7
        const val VERTICAL_PIECES = 3
    }
}